<?php

namespace Pinenut;

use Pinenut\Model2;
use Pinenut\Model2\Embedded\Assoc;
use Pinenut\Files\File;

/**
 * Хранилище файлов и сопутствующих данных
 *
 *
 * @author kosh
 *        
 */
abstract class Files extends Model2 {

	protected $_thumbsConfigClass;// = '\Files\ThumbsConfig';
	
	/**
	 * @var \Pinenut\Files\File
	 */
	public $file;
	/**
	 * @var \Pinenut\Files\File[]
	 */
	public $thumbs;
	
	
	function fields() {
		return array_merge ( parent::fields (), [
			'file' => File::className (), 
			'thumbs' => [
				Assoc::className (), 
				File::className (), 
			],
		]);
	}
	
	
	static function create($filename, $params = []) {
		// создаем
		$file = new static;
		$file->populate($params, false);
		
		// сохраняем файл в систему хранения
		$file->file->putFile($filename);
		
		//генерим ноготки если надо
		
		// делаем еще что-нить
		
		// сейвим всё
		$file->save();
		
		return $file;
	}
	
	function getThumb($name) {
		// проверяем по конфе - доступен ли такой формат 
		$configClass = $this->_thumbsConfigClass;
		$config = $configClass::get($name);
		
		if (empty($config)) {
			throw new \Exception('Wrong thumbnail', 404);
		}
		
		if (!isset($this->thumbs[$name])) {
			// ногтя не существует - отдаём на генерацию
			$this->renderThumb($name, $config);
			
		}
		
		return $this->thumbs[$name];
		
	}
	
	function renderThumb($name, array $config) {
		// если бмп грузим одиим способом, иначе как обычно
		
		$image = $this->loadImage();
		
		$image = $this->resizeImage($image, $config);
		
		$filename = $this->compressImage($image, $config);
		
		$this->thumbs[$name]->putFile($filename);
		
		$this->save();
	}
	
	function loadImage() {
		
		if (preg_match('/^image\/.*bmp$/i', $this->file->mimeType)){
			$image = static::imagecreatefrombmp($this->file->getBytes());
		} else {
			$image = imagecreatefromstring($this->file->getBytes());
		}
		
		return $image;
	}
	
	function resizeImage($image, $config) {
		
		$targetWidth = $config['width'];
		$targetHeight = $config['height'];
		$resize = $config['resize'];
		
		// ресайзим в зависимости от типа
		switch ($resize) {
		
			case 'crop': // вписываем в область, обрезая не поместившееся
		
				$width = imagesx($image);
				$height = imagesy($image);
				// 				echo $width . 'x' . $height . '<br>';
		
// 				if ($this->getOwner()->cropCoords && (
// 						preg_match('/([0-9\.]+),([0-9\.]+);([0-9\.]+),([0-9\.]+)/', $this->getOwner()->cropCoords, $m))
// 						&& ($m[3] - $m[1] > 0 && $m[4] - $m[2] > 0)) {
// 					$xCorrection = round($width * $m[1]);
// 					$yCorrection = round($height * $m[2]);
		
// 					$width = round($width * ($m[3] - $m[1]));
// 					$height = round($height * ($m[4] - $m[2]));
		
// 					//					$targetWidth = $width;
// 					//					$targetHeight = $height;
// 				} else {
 					$xCorrection = $yCorrection = 0;
// 				}
		
				$ratio = $width / $height;
				if ($targetWidth / $targetHeight > $ratio) {
					$newHeight = $targetWidth / $ratio;
					$newWidth = $targetWidth;
				} else {
					$newWidth = $targetHeight * $ratio;
					$newHeight = $targetHeight;
				}
		
				$horizontalMiddle = $newWidth / 2;// + $xCorrection;
				$verticalMiddle = $newHeight / 2;// + $yCorrection;
		
				// масштабируем
				$process = imagecreatetruecolor(round($newWidth), round($newHeight));
				ImageAlphaBlending($process, true);
		
				//Если мы не трогали переменную fill -
				//пустота на картинке будет заполняться указанным цветом
				//Внесённые дополнения для спрайтогенерации
		
				//				if($fill) imagefill($process, 0, 0, 0xffffff);
		
				imagecopyresampled($process, $image, 0, 0, $xCorrection, $yCorrection, $newWidth, $newHeight, $width, $height);
		
				// кроп
				$image = imagecreatetruecolor($targetWidth, $targetHeight);
				//				ImageAlphaBlending($image, true);
		
				//				imagefill($idest, 0, 0, 0xffffff);
				imagecopyresampled($image, $process, 0, 0,
				($horizontalMiddle-($targetWidth/2)), ($verticalMiddle-($targetHeight/2)),
				$targetWidth, $targetHeight, $targetWidth, $targetHeight);
		
				imagedestroy($process);
				break;
		
			default:
			case 'fit': // вписываем в область, сохраняя пропорции сторон. Но большая сторона не может превышать заданные размеры
			case 'fat': // вписываем в область по меньшей стороне. эта шляпатень нужна для галерейки, когда картинки движутся во всякие стороны
			case 'fit-if-needed': // вписываем в облать, если не влазит, и не увеличиваем, если картинка меньше ограничений
				$width = imagesx($image);
				$height = imagesy($image);
		
				$horizontalRatio = $targetWidth / $width;
				$verticalRatio = $targetHeight / $height;
					
				$ratio = ('fat' == $resize) ? max($horizontalRatio, $verticalRatio) : min($horizontalRatio, $verticalRatio);
				$useHorizontalRatio = ($horizontalRatio == $ratio);
		
				$newWidth   = $useHorizontalRatio  ? $targetWidth  : floor($width * $ratio);
				$newHeight  = !$useHorizontalRatio ? $targetHeight : floor($height * $ratio);
		
				if ('fit-if-needed' == $resize) {
					if (($newWidth > $width) || ($newHeight > $height)) {
						$newWidth = $width;
						$newHeight = $height;
					}
				}
					
				$processImage = imagecreatetruecolor($newWidth, $newHeight);
				ImageAlphaBlending($processImage, true);
					
				//Если мы не трогали переменную fill -
				//пустота на картинке будет заполняться указанным цветом
				//Внесённые дополнения для спрайтогенерации
				//				if($fill)imagefill($idest, 0, 0, 0xffffff);
					
				imagecopyresampled($processImage , $image, 0, 0, 0, 0,
				$newWidth, $newHeight, $width, $height);
		
				$image = $processImage;
				break;
		}
		
		return $image;
		
	}
	
	function compressImage($image, $config) {
		
		$targetType = @$config['type'];
		$targetQuality = @$config['quality'];
		
		// сохраняем
		if (null === $targetType)
			list (,$targetType) = explode('/', $this->file->mimeType);
		
		// сохраняем через жооопу - т.е. через файлы... сначала в файл генерим картинку,
		// потом её из того же места скармливаем gridfs
		$filename = tempnam('/tmp', 'thumbnail_');
		
		switch ($targetType) {
			case 'jpeg':
				if (null === $targetQuality) imagejpeg($image, $filename);
				else imagejpeg($image, $filename, $targetQuality);
				break;
			case 'png':
				if (null === $targetQuality) imagepng($image, $filename);
				else imagepng($image, $filename, $targetQuality>9?9:$targetQuality);
				break;
		
			case 'gif':
				if (null === $targetQuality) imagegif($image, $filename);
				else imagegif($image, $filename, $targetQuality);
				break;
			default:
				break;
		}
		
		return $filename;
	}
	
	
	static public function imagecreatefrombmp($read)
	{
		//    Load the image into a string
		// 		$file    =    fopen($p_sFile,"rb");
		// 		$read    =    fread($file,10);
		// 		while(!feof($file)&&($read<>""))
			// 			$read    .=    fread($file,1024);
	
		$temp    =    unpack("H*",$read);
		$hex    =    $temp[1];
		$header    =    substr($hex,0,108);
	
		//    Process the header
		//    Structure: http://www.fastgraph.com/help/bmp_header_format.html
		if (substr($header,0,4)=="424d")
		{
			//    Cut it in parts of 2 bytes
			$header_parts    =    str_split($header,2);
	
			//    Get the width        4 bytes
			$width            =    hexdec($header_parts[19].$header_parts[18]);
	
			//    Get the height        4 bytes
			$height            =    hexdec($header_parts[23].$header_parts[22]);
	
			//    Unset the header params
			unset($header_parts);
		}
	
		//    Define starting X and Y
		$x                =    0;
		$y                =    1;
	
		//    Create newimage
		$image            =    imagecreatetruecolor($width,$height);
	
		//    Grab the body from the image
		$body            =    substr($hex,108);
	
		//    Calculate if padding at the end-line is needed
		//    Divided by two to keep overview.
		//    1 byte = 2 HEX-chars
		$body_size        =    (strlen($body)/2);
		$header_size    =    ($width*$height);
	
		//    Use end-line padding? Only when needed
		$usePadding        =    ($body_size>($header_size*3)+4);
	
		//    Using a for-loop with index-calculation instaid of str_split to avoid large memory consumption
		//    Calculate the next DWORD-position in the body
		for ($i=0;$i<$body_size;$i+=3)
		{
			//    Calculate line-ending and padding
			if ($x>=$width)
			{
				//    If padding needed, ignore image-padding
				//    Shift i to the ending of the current 32-bit-block
				if ($usePadding)
					$i    +=    $width%4;
	
				//    Reset horizontal position
				$x    =    0;
	
				//    Raise the height-position (bottom-up)
				$y++;
	
				//    Reached the image-height? Break the for-loop
				if ($y>$height)
					break;
			}
	
			//    Calculation of the RGB-pixel (defined as BGR in image-data)
			//    Define $i_pos as absolute position in the body
			$i_pos    =    $i*2;
			$r        =    hexdec($body[$i_pos+4].$body[$i_pos+5]);
			$g        =    hexdec($body[$i_pos+2].$body[$i_pos+3]);
			$b        =    hexdec($body[$i_pos].$body[$i_pos+1]);
	
			//    Calculate and draw the pixel
			$color    =    imagecolorallocate($image,$r,$g,$b);
			imagesetpixel($image,$x,$height-$y,$color);
	
			//    Raise the horizontal position
			$x++;
		}
	
		//    Unset the body / free the memory
		unset($body);
	
		//    Return image-object
		return $image;
	}
}